﻿using System;
using System.Collections.Generic;
using System.Xml.Serialization;
using MongoDB.Bson;
using MongoDB.Driver;
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Driver.Builders;

namespace MongoCamp
{
    /// <summary>
    /// EntityCollection generic base class
    /// </summary>
    /// <typeparam name="TPrimaryKeyType">The primary key id type</typeparam>
    /// <typeparam name="TEntityClass">The entity class name</typeparam>
    public abstract class EntityCollection<TPrimaryKeyType, TEntityClass> : EntityQueryProvider<TPrimaryKeyType, TEntityClass>, IEntityCollection
        where TEntityClass : IEntityCollection, new()
    {
        #region constructor method
        /// <summary>
        /// no parameter constructor
        /// (The collectioName = current class name, 
        /// MongoServer = MongoServerPack.DefaultDB)
        /// </summary>
        protected EntityCollection()
        {
            _collectionName = typeof(TEntityClass).Name;
            _mongoServer = MongoServerPack.DefaultDB;
        }

        /// <summary>
        /// constructor by collectionName
        /// (MongoServer = MongoServerPack.Default)
        /// </summary>
        /// <param name="collectionName">specify collection name</param>
        protected EntityCollection(string collectionName)
            : this()
        {
            _collectionName = collectionName;
        }

        /// <summary>
        /// constructor by mongoServer
        /// (collectioName = current class Name)
        /// </summary>
        /// <param name="mongoServer">specify MongoServer pack</param>
        protected EntityCollection(MongoServerPack mongoServer)
            : this()
        {
            _mongoServer = mongoServer;
        }

        /// <summary>
        /// constructor by collectionName and mongoServer
        /// </summary>
        /// <param name="collectionName">specify collectionName</param>
        /// <param name="mongoServer">specify MongoServer Pack</param>
        protected EntityCollection(string collectionName, MongoServerPack mongoServer)
        {
            _collectionName = collectionName;
            _mongoServer = mongoServer;
        }
        #endregion  constructor method

        #region IEntityCollection method

        /// <summary>
        /// Get current collection name
        /// </summary>
        /// <returns>string</returns>
        public virtual string GetCollectionName()
        {
            return _collectionName;
        }

        /// <summary>
        /// Get current MongoServer
        /// </summary>
        /// <returns></returns>
        public virtual MongoServerPack GetMongoServer()
        {
            return _mongoServer;
        }

        private readonly string _collectionName;
        private readonly MongoServerPack _mongoServer;

        #endregion IEntityCollection method

        #region PrimaryKeyID Get&Set method
        // ReSharper disable InconsistentNaming
        /// <summary>
        /// EntityCollection PrimaryKeyID
        /// </summary>
        [BsonId]
        [XmlIgnore]
        public TPrimaryKeyType PrimaryKeyID { get; set; }

        /// <summary>
        /// Get EntityCollection PrimaryKeyID
        /// </summary>
        /// <returns>PrimaryKeyID</returns>
        public virtual TPrimaryKeyType GetPrimaryKeyID()
        {
            return PrimaryKeyID;
        }

        /// <summary>
        /// Set EntityCollection PrimaryKeyID
        /// </summary>
        /// <param name="value">new PrimaryKeyID value</param>
        public virtual void SetPrimaryKeyID(TPrimaryKeyType value)
        {
            PrimaryKeyID = value;
        }
        // ReSharper restore InconsistentNaming

        #endregion PrimaryKeyID Get&Set method

        #region Save method

        /// <summary>
        /// Save instance by PrimaryKeyID
        /// </summary>
        /// <param name="primaryKey">PrimaryKeyID</param>
        /// <returns>WriteConcernResult</returns>
        public virtual WriteConcernResult Save(TPrimaryKeyType primaryKey)
        {
            SetPrimaryKeyID(primaryKey);
            return this.Save();
        }
        #endregion Save method
    }
}
